package com.github.zxhtom.base.config;


import com.github.zxhtom.base.constant.CoreConstants;
import com.github.zxhtom.base.exception.BusinessException;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;

@ControllerAdvice
public class ResponseBodyHandler implements ResponseBodyAdvice<Object> {
    private static Logger logger = LoggerFactory.getLogger(ResponseBodyHandler.class);

    @Override
    public boolean supports(MethodParameter methodParameter, Class<? extends HttpMessageConverter<?>> aClass) {
        if (methodParameter == null) {
            return false;
        }
        // 仅处理包头前缀为com.zxhtom的Controller请求返回值
        return methodParameter.getContainingClass().getPackage().getName().startsWith(CoreConstants.PACKAGE_PREFIX);
    }

    @Override
    public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
        if (body == null) {
            return new ActionResult(ActionResultCode.SUCCESS.getValue(), null, null);
        }
        // body是异常, 代表失败
        if (body instanceof Exception) {
            // 异常写日志
            Exception ex = (Exception) body;
            if (logger.isErrorEnabled()) {
                logger.error(ExceptionUtils.getStackTrace(ex));
            }

            // BusinessException业务异常返回ErrorCode, message
            if (body instanceof BusinessException) {
                BusinessException bex = (BusinessException) body;
                return new ActionResult(bex.getErrorCode(), bex.getMessage(), null);
            }
            // IllegalArgumentException / NullPointerException /
            // IndexOutOfBoundsException / IllegalStateException
            // 错误消息不为空, 参数检查抛出的异常, 认为也是业务异常
            if (body instanceof IllegalArgumentException || body instanceof NullPointerException || body instanceof IndexOutOfBoundsException || body instanceof IllegalStateException) {
                String message = ex.getMessage();
                if (StringUtils.isNotEmpty(message)) {
                    return new ActionResult(ActionResultCode.BUSINESS_ERROR.getValue(), message, null);
                }
            }

            // BindException / MethodArgumentNotValidException 是 Spring MVC
            // Controller 参数实体校验异常, 也认为是业务异常
            BindingResult bindingResult = null;
            if (body instanceof BindException) {
                bindingResult = ((BindException) body).getBindingResult();
            }
            if (body instanceof MethodArgumentNotValidException) {
                bindingResult = ((MethodArgumentNotValidException) body).getBindingResult();
            }
            if (bindingResult != null && bindingResult.hasErrors()) {
                return new ActionResult(ActionResultCode.BUSINESS_ERROR.getValue(), ErrorUtil.getErrorsMessage(bindingResult), null);
            }

            return new ActionResult(ActionResultCode.OTHER_ERROR.getValue(), ex.toString(), null);
        }

        // 返回数据
        ActionResult result = new ActionResult(ActionResultCode.SUCCESS.getValue(), null, body);
        return result;
    }
}
